----------------Quations---------------
A 4am crack                  2014-11-19
-------------------. updated 2017-12-03
                   |___________________

"Quations" is a 1985 educational game
developed by Bernie Dodge and Steven
Buss of Edaptive Software, and
distributed by Scholastic. It is based
on the board game of the same name,
which was originally created in 1973 by
Andrew P. Mandell.

[The copy protection is identical to
several other titles I've seen before,
including

- "Gertrude's Secrets, "Bumble Games,"
  "Juggles' Rainbow, "Moptown Parade,"
  "Reader Rabbit," and "Wizard of
  Words" by The Learning Company

- "Xevious" by Mindscape

- "The Notable Phantom" by DesignWare

- "Animal Kingdom" and "Race Car
  'Rithmetic" by Unicorn Software

- "Pitstop II" by Epyx

- "Microzine" issues 12, 13, 17, and 18
  by Scholastic

Somebody been sellin' copy protection.

Anyway, this write-up is quite similar
to those, except that my AUTOTRACE
program has gotten smarter over time,
so more of the process is automated.]

Booting the disk looks and sounds like
a normal DOS 3.3 boot, complete with
the drive seeking to track 2, then 1,
then 0, then swinging to the middle of
the disk to read the catalog track. It
even displays a BASIC prompt during
boot, as if it's loading a boot program
(like "HELLO").

However, the disk is uncopyable by any
automated method. COPYA fails miserably
and immediately. EDD 4 bit copy gives
no read errors, but the copy it creates
only gets as far as loading DOS and
displaying the BASIC prompt before
filling the screen with garbage and
rebooting.

In my experience, disks do not
spontaneously reboot unless someone
tells them to.

Turning to my trusty Disk Fixer sector
editor, I press "O" to get to the
Input/Output Control and set "CHECKSUM
ENABLED" to "NO". This will ignore the
checksum bytes and epilogue sequences.
i.e. As long as the address and data
prologue are standard ("D5 AA 96" and
"D5 AA AD", respectively), this will
allow me to read each sector. And lo
and behold, it works! I can read the
data from every sector on every track.

Track $11 does appear to contain a disk
catalog, which strongly suggests this
disk is file-based.

Based on my limited experience cracking
other disks, I would guess that this
disk has

- Standard prologue bytes before the
  address and data fields [otherwise
  Copy ][+ sector editor would give
  read errors, even with the "DOS 3.3
  PATCHED" option]

- Non-standard epilogue bytes after the
  address and data fields [otherwise
  COPYA would work]

- Some secondary protection [otherwise
  the bit copy created with EDD 4 would
  work]

Given the (relatively) weak structural
protection, I used to turn to the DOS
3.3 master disk, patch the RWTS to
ignore checksums and epilogue bytes
(changing $B942 from "SEC" to "CLC"),
and run COPYA. Then, one fine day, and
completely by accident, I came across
an original disk with a bad sector. I
suppose this shouldn't surprise me.
These floppies are decades old by now;
it's amazing any of them work at all.

The point is, I shouldn't be using
tools that ignore potentially serious
read errors. So, no more COPYA+B942:18
patch. From now on, it's Super Demuffin
or Advanced Demuffin to convert disks
to a standard format.

Just by looking at the first few
sectors, it appears that this disk uses
a DOS 3.3-derived RWTS, which means
that my AUTOTRACE program should be
able to extract the RWTS from the
original disk.

[S6,D1=original disk]
[S5,D1=my work disk]

]PR#5
...
CAPTURING BOOT0
...reboots slot 6...
...reboots slot 5...
SAVING BOOT0
/!\ BOOT0 JUMPS TO $08C0
CAPTURING BOOT1
...reboots slot 6...
...reboots slot 5...
SAVING BOOT1
SAVING RWTS
/!\ NIBBLE CHECK AT $BB00

For those of you just tuning in, my
work disk uses a custom program that I
affectionately call "AUTOTRACE" to
automate the process of boot tracing as
far as possible. For some disks, this
just captures track 0, sector 0 (saved
in a file called "BOOT0") and stops.
For other disks that load in the same
way that an unprotected DOS 3.3 disk
loads, it captures the next stage of
the boot process as well (in a file
acalled "BOOT1"). BOOT1 contains sectors
0-9 on track 0, which are loaded into
memory at $B600..$BFFF. This generally
contains the RWTS routines which the
program uses to read the rest of the
disk.

If the RWTS is fairly normal as well
(and my AUTOTRACE program just spot-
checks a few memory locations to guess
at its "normalcy"), there's a good
chance I'll be able to use a tool
called Advanced Demuffin (written in
1983 by The Stack) to convert the disk
from whatever weird format it uses to
store its sector data into a standard
disk readable by unprotected DOS 3.3
disks or any other third-party tools.
In this case, AUTOTRACE extracts the
RWTS routines (generally loaded from
track 0, sectors 2-9 into $B800..$BFFF)
and saves *that* into a third file
called "RWTS".

If anything looks fishy or non-
standard, AUTOTRACE just stops, and I
have to check the files it saved so far
to determine why. But in this case, it
ran all the way through, automatically
capturing BOOT0, BOOT1, and RWTS files.
Now I can use Advanced Demuffin to
convert the disk to a standard format.
(It uses the disk's own RWTS to read
the original, then a standard DOS 3.3-
compatible RWTS to write out the data,
sector by sector.)

Along the way, AUTOTRACE gave me two
different warnings, which is very
exciting(*). I just added the warnings
recently, and here I am already reaping
the benefits.

(*)not guaranteed, excitement may vary

Let's see what the first one is about.

/!\ BOOT0 JUMPS TO $08C0

]BLOAD BOOT0,A$800
]CALL -151

*801L
...

Everything here looks pretty normal
(i.e. just like an unprotected DOS 3.3
disk), until it goes to jump to the
boot1 code. Usually that happens with
an indirect JMP ($08FD), which, in a
normal boot0, will end up continuing
execution at $B700 which is stored in
track 0, sector 1. But in this case, I
see:

084A-   4C C0 08    JMP   $08C0

*8C0L

08C0-   8E E9 B7    STX   $B7E9
08C3-   6C FD 08    JMP   ($08FD)

I've seen this pattern before on other
disks -- "Gertrude's Secrets" and
"Xevious", just to name two. It usually
means that some code at $B700 will be
calling a subroutine that I don't
particularly want it to call (like a
nibble check).

The second warning provides additional
evidence of this:

/!\ NIBBLE CHECK AT $BB00

I'll deal with that later. Right now I
want to focus on converting this disk
to a standard format. I have the RWTS
and can load it into Advanced Demuffin.

[S6,D1=original disk]
[S6,D2=blank disk]
[S5,D1=my work disk]

]PR#5
...

]BRUN ADVANCED DEMUFFIN 1.5

[press "5" to switch to slot 5]

[press "R" to load a new RWTS module]
  --> At $B8, load "RWTS" from drive 1

[press "6" to switch to slot 6]

[press "C" to convert disk]

This disk is 16 sectors, and the
default options (copy the entire disk,
all tracks, all sectors) don't need to
be changed unless something goes
horribly wrong.

                 --v--

ADVANCED DEMUFFIN 1.5    (C) 1983, 2014
ORIGINAL BY THE STACK    UPDATES BY 4AM
=======PRESS ANY KEY TO CONTINUE=======
TRK:...................................
+.5:
    0123456789ABCDEF0123456789ABCDEF012
SC0:...................................
SC1:...................................
SC2:...................................
SC3:...................................
SC4:...................................
SC5:...................................
SC6:...................................
SC7:...................................
SC8:...................................
SC9:...................................
SCA:...................................
SCB:...................................
SCC:...................................
SCD:...................................
SCE:...................................
SCF:...................................
=======================================
16SC $00,$00-$22,$0F BY1.0 S6,D1->S6,D2

                 --^--

The disk's own RWTS gave no read errors
on any track. This is the power and the
genius of Advanced Demuffin. Every disk
must be able to read itself. So, let it
read itself, then capture the data and
write it out in a standard format.

There are two problems with this copy:

1. Depending on how the original disk
   was written, this copy may or may
   not be able to read itself. I may
   need to patch the disk's RWTS to
   deal with the fact that the disk is
   now in a standard format.

2. Even if it can read itself, it won't
   run. The copies I tried to make --
   even the bit copies -- just rebooted
   endlessly, which means there is some
   code being executed during boot to
   check if the disk is original.
   (Hint: it's not.)

Just by booting my copy, I can rule out
problem #1. The disk seems to read
itself just fine. It makes it exactly
as far as my failed bit copy -- far
enough to figure out that it's not an
original disk, fill the screen with
garbage, and reboot.

But wait...

]PR#5
...

]CATALOG,S6,D2

C1983 DSR^C#254
008 FREE

*A 006 HELLO
*B 031 Q1-TITLE
*A 004 Q2-LOADER
*B 080 Q3-INPUT
*B 076 Q4-ANALYSIS
*B 068 Q4-MOVE
*B 071 Q4-QUATO
*B 039 Q5-END
 T 002 HIGHSCORE
*B 003 GAMEDATA.NEW
*B 005 HPRINT ANIM
*B 006 HPRINT ALONE
*B 036 QUATOX.ANM
*B 017 RUNTIME
*B 002 SOUNDS
*B 002 FASTCLEAR
*B 005 ST.SQUATO
*B 019 ST.QWORD1
*B 010 ST.TILES.NEW
*B 006 ST.SCHOLASTIC

]RUN HELLO

The disk boots and runs without
complaint (even from drive 2). This
tells me that there isn't any
coordination with or reliance on the
custom DOS once the program loads.
(Some programs manually check for
specific non-standard values in the DOS
area in memory. But I don't see any
evidence of that here.)

Let's back up and take a look at that
nibble check.

]PR#5
...

]BLOAD BOOT1,A$2600
]CALL -151

*FE89G FE93G     ; disconnect DOS

*B600<2600.2FFFM ; move RWTS into place

*B700L

B700-   20 00 BB    JSR   $BB00

I've learned from previous cracks (and
from actually reading "Beneath Apple
DOS" instead of, you know, just staring
at it on my bookshelf) that, in a
standard DOS-3.3-derived RWTS, the area
from $BB00 to $BC55 is overwritten
during every disk read. (It's used as
scratch space during denibblization,
which is totally a real word that I
just made up.)

So why is there executable code there?
Let's find out.

*BB00L

BB00-   A0 00       LDY   #$00
BB02-   B9 00 BB    LDA   $BB00,Y
BB05-   99 00 02    STA   $0200,Y
BB08-   88          DEY
BB09-   D0 F7       BNE   $2B02
BB0B-   60          RTS

Well that's definitely suspicious.
Relocating yourself into the input
buffer at $0200? Seriously, who does
that?

I'm guessing that the first instruction
after this is the entry point, so after
relocation, that would be $020C.

*20C<BB0C.BBFFM

*20CL

; this subroutine seeks to track $11
; and sets the reset vector to
; something unfriendly
020C-   20 CF 02    JSR   $02CF
020F-   A9 0A       LDA   #$0A
0211-   85 2A       STA   $2A

; initialize disk motor
; (highly suspicious)
0213-   AE E9 B7    LDX   $B7E9
0216-   BD 89 C0    LDA   $C089,X
0219-   BD 8E C0    LDA   $C08E,X

; set some counters
021C-   A9 C7       LDA   #$C7
021E-   85 48       STA   $48
0220-   A9 02       LDA   #$02
0222-   85 49       STA   $49
0224-   A9 80       LDA   #$80
0226-   85 29       STA   $29
0228-   C6 29       DEC   $29

; reboots (bad)
022A-   F0 67       BEQ   $0293

; position the drive head to where the
; nibble check needs it
022C-   20 44 B9    JSR   $B944
022F-   B0 62       BCS   $0293
0231-   A5 2D       LDA   $2D
0233-   C9 0D       CMP   #$0D
0235-   D0 F1       BNE   $0228
0237-   A0 00       LDY   #$00
0239-   BD 8C C0    LDA   $C08C,X
023C-   10 FB       BPL   $0239
023E-   88          DEY

; reboots (bad)
023F-   F0 52       BEQ   $0293

; Search for a specific sequence of
; nibbles in the "dead zone" between
; the address field and data field.
; This area is normally not important,
; so COPYA didn't copy it precisely
; because normal disks don't care.
; (Actually, it's even more evil than
; that, because the original disk is
; written with timing bits in specific
; non-standard places between the
; nibbles in the dead zone. This code
; not only requires the right nibbles
; in the right order, it reads them
; just slightly slower than normal. So
; the timing bits need to be in the
; right places too, or else this code
; will read the wrong nibble values
; while it's out of sync. This will
; trip up even the best bit copiers.
; And you can forget about making a
; disk image for emulators -- those
; don't store timing bits at all.)
0241-   C9 D5       CMP   #$D5
0243-   D0 F4       BNE   $0239
0245-   A0 00       LDY   #$00
0247-   BD 8C C0    LDA   $C08C,X
024A-   10 FB       BPL   $0247
024C-   88          DEY

; reboots (bad)
024D-   F0 44       BEQ   $0293
024F-   C9 E7       CMP   #$E7
0251-   D0 F4       BNE   $0247
0253-   BD 8C C0    LDA   $C08C,X
0256-   10 FB       BPL   $0253
0258-   C9 E7       CMP   #$E7

; reboots (bad)
025A-   D0 37       BNE   $0293
025C-   BD 8C C0    LDA   $C08C,X
025F-   10 FB       BPL   $025C
0261-   C9 E7       CMP   #$E7

; reboots (bad)
0263-   D0 2E       BNE   $0293

; kill some time to get out of sync
; with the "proper" start of nibbles)
0265-   BD 8D C0    LDA   $C08D,X
0268-   A0 10       LDY   #$10
026A-   24 06       BIT   $06

; now start looking for nibbles that
; don't really exist (except they do,
; because we're out of sync and reading
; timing bits as data)
026C-   BD 8C C0    LDA   $C08C,X
026F-   10 FB       BPL   $026C
0271-   88          DEY

; reboots (bad)
0272-   F0 1F       BEQ   $0293
0274-   C9 EE       CMP   #$EE
0276-   D0 F4       BNE   $026C

; check for nibble sequence stored
; in reverse order at $2C7
0278-   A0 07       LDY   #$07
027A-   BD 8C C0    LDA   $C08C,X
027D-   10 FB       BPL   $027A
027F-   D1 48       CMP   ($48),Y
0281-   D0 10       BNE   $0293
0283-   88          DEY
0284-   10 F4       BPL   $027A

; if we made it this far, the nibble
; check passed
0286-   A9 80       LDA   #$80
0288-   8D 4E 9E    STA   $9E4E
028B-   A9 A1       LDA   #$A1
028D-   8D 4F 9E    STA   $9E4F
0290-   4C 4D 9E    JMP   $9E4D

That last section at $0286..$0290 is
interesting. After the nibble check
passes, it replaces two bytes at $9E4E
and $9E4F, then immediately jumps to
$9E4D. That implies that this nibble
check is called from $9E4D via an
unconditional jump (not a JSR). With my
trusty Disk Fixer sector editor, I
searched the disk for "4C 0C 02" and
lo and behold! Track $00, sector $0B,
byte $4D contains a "JMP $020C".

If I'm reading this correctly, I should
be able to change that JMP back to its
original target ($A180) and bypass the
nibble check altogether.

A lot of disks need this sort of post-
demuffin patching, and I got tired of
doing it manually, so I wrote a program
to do it for me. It is called,
unsurprisingly, Post-Demuffin Patcher.
It prompts you to select a slot and
drive, then reads the demuffin'd disk,
checks for a modified DOS 3.3-shaped
RWTS, and applies the necessary patches
so the disk can read itself. (It can
also detect and bypass some nibble
checks, like this one.) I've included a
copy of Post-Demuffin Patcher on my
work disk; the full source code is
currently available at
<https://archive.org/details/
PostDemuffinPatcher4am>.

[S6,D1=demuffin'd copy]
[S5,D1=my work disk]

]PR#5
...

]BRUN PDP

T00,S0B,$4E change 0C02 to 80A1

(This is the actual output of the
program. Post-Demuffin Patcher prints
out the changes it is going to make
before it writes them to the disk.)

As you can see, PDP came to the same
conclusion I did (but, you know, much
faster). The only patch this disk needs
to bypass the nibble check is to jump
to $A180 instead of $020C.

]PR#6

Success! The disk boots and runs with
no complaint. There doesn't appear to
be any further protection.

Side B is unprotected.

Quod erat liberandum.

                   ~

               Changelog


2017-12-03

- added missing side B (no changes to
  side A)

2014-11-19

- initial release

---------------------------------------
A 4am crack                     No. 167
------------------EOF------------------
